package com.huang.base;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Optional;

/**
 * RPC调用抽象类
 * 记录日志和耗时
 * <p>
 * AbstractIntegrationFactoryBean
 *
 * @author huangshen
 * @since 2022/02/24
 */

public abstract class AbstractIntegrationFactoryBean<T> implements FactoryBean<T> {

    private final static Logger logger = LoggerFactory.getLogger(AbstractIntegrationFactoryBean.class);


    @Override
    public T getObject() throws Exception {
        Class<T> clazz = getTargetClass();
        Object object = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new IntegrationInvocationHandler());
        return (T) object;
    }

    @Override
    public Class<?> getObjectType() {
        return getTargetClass();
    }

    protected abstract T getTarget();

    protected abstract Class<T> getTargetClass();

    private class IntegrationInvocationHandler implements InvocationHandler {

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            long startTime = System.currentTimeMillis();
            String classSimpleName = getTargetClass().getSimpleName();
            String methodName = method.getName();

            try {
                logger.info("请求接口类[{}]方法[{}]开始调用，参数args[{}]", classSimpleName, methodName, args);
                result = method.invoke(getTarget(), args);
            } catch (Exception e) {
                logger.error("接口类[{}]方法[{}]调用异常", classSimpleName, methodName, e);
                throw e;
            }

            long endTime = System.currentTimeMillis();
            // 返回参数打印
            logger.info("接口类[{}]方法[{}]调用成功，耗时[{}ms],result[{}]", classSimpleName, methodName, (endTime - startTime), result);

            if (!Optional.ofNullable(result).isPresent()) {
                throw new Exception("RPC未找到数据");
            }
            // 返回结果校验

            return result;
        }
    }


}
